package com.ec.edu.advice;

import com.ec.edu.exception.CommonException;
import com.ec.edu.exception.CommonExceptionEnum;
import com.ec.edu.response.ErrorResponseData;
import com.ec.edu.response.ResponseData;
import com.ec.edu.response.SuccessResponseData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import javax.servlet.http.HttpServletResponse;

/**
 * 全局的的异常拦截器（拦截所有的控制器）（带有@RequestMapping注解的方法上都会拦截）
 *
 * @author jxyang
 */
@Slf4j
@ControllerAdvice
public class DefaultControllerAdvice implements ResponseBodyAdvice
{

    @Override
    public boolean supports(MethodParameter methodParameter, Class aClass) {
        return true;
    }

    /**
     * 封装返回结果
     * @param returnValue
     * @param methodParameter
     * @param mediaType
     * @param aClass
     * @param serverHttpRequest
     * @param serverHttpResponse
     * @return
     */
    @Override
    public Object beforeBodyWrite(Object returnValue, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {

        //如果已经是ResponseData，直接返回
        if ( returnValue instanceof ResponseData) {
            return returnValue;
        }
        else if ( returnValue instanceof String ){
            try {
                return SuccessResponseData.success(returnValue);
            }catch (Exception e){
                log.error("返回结果转换json异常",e);
                return ErrorResponseData.error("返回结果转换json异常");
            }
        }
        return SuccessResponseData.success(returnValue);
    }

    /**
     * 拦截common异常
     */
    @ExceptionHandler(CommonException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ResponseBody
    public ResponseData serviceException(CommonException e)
    {
        log.error("服务端业务异常:", e);
        return new ErrorResponseData(e.getCode(), e.getErrorMessage());
    }


    /**
     * 拦截未知的运行时异常
     */
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public ResponseData notFount(Exception e, HttpServletResponse reponse)
    {
        if (HttpStatus.NOT_FOUND.value() == reponse.getStatus())
        {
            log.error(CommonExceptionEnum.NO_FOUNT.getMessage(), e);
            return new ErrorResponseData(CommonExceptionEnum.NO_FOUNT.getCode(), CommonExceptionEnum.NO_FOUNT
                    .getMessage());
        }
        log.error(CommonExceptionEnum.SYSTEM_ERROR.getMessage(), e);
        reponse.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
        return new ErrorResponseData(CommonExceptionEnum.SYSTEM_ERROR.getCode(), CommonExceptionEnum.SYSTEM_ERROR
                .getMessage());
    }

    @ExceptionHandler({MethodArgumentNotValidException.class})
    @ResponseBody
    public ErrorResponseData handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        BindingResult result = e.getBindingResult();
        FieldError error = result.getFieldError();
        String field = error.getField();
        String code = error.getDefaultMessage();
        String message = String.format("%s:%s", field, code);
        log.warn("参数验证失败：" + message);
        return new ErrorResponseData("参数验证失败：" + message);
    }



}
